package com.example.tkserver.controller;

import com.example.tkserver.config.RabbitMqConfig;
import com.example.tkserver.config.ServerEncoder;
import com.example.tkserver.dao.RedisCacheDao;
import com.example.tkserver.entity.MyMessage;
import com.example.tkserver.entity.MyException;
import com.example.tkserver.utils.response.ResultData;
import com.rabbitmq.client.Channel;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description: WebSocket接口
 * @Auther: LiZhuoYi
 * @Date: 10/11/2022
 */
@Log4j2
@Component
//把当前类标识成一个WebSocket的服务端，值是访问的URL地址
@ServerEndpoint(value = "/websocket/{uid}",encoders = {ServerEncoder.class})
public class WebSocketServer{
    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    private String uid;

    //存放session的集合，很重要！！
    private static ConcurrentHashMap<String, WebSocketServer> sessions = new ConcurrentHashMap<>();
    //消息缓存
    private static RedisCacheDao redisCacheDao;

    @Autowired
    public void setRedisCacheDao(RedisCacheDao rcd){
        redisCacheDao = rcd;
    }

    //监听公共队列，从队列中把刚发送的消息取出来
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RabbitMqConfig.COMMON_TOPIC),
            exchange = @Exchange(value = RabbitMqConfig.COMMON_EXCHANGE,type = ExchangeTypes.FANOUT)
    ))
    public void getCommonMessAge(MyMessage message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {
        try {
            log.info("收到消息：" + message);
            channel.basicAck(tag, false); //反馈ack
            //获取接收者
            String rid = String.valueOf(message.getRid());
            WebSocketServer webSocketServer = sessions.get(rid);
            log.info("查询连接:"+rid+","+webSocketServer);
            //如果接收者已连接
            if (webSocketServer != null){
                // 直接发给这个人
                webSocketServer.sendMessage(message);
            }else{
                List<MyMessage> dat = new ArrayList<>();
                List<MyMessage> messages = redisCacheDao.getList(rid,MyMessage.class);
                if (messages != null){
                    dat.addAll(messages);
                }
                dat.add(message);
                //更新缓存数据
                redisCacheDao.add(rid,dat);
            }
        }catch (Exception e){
            log.error("发生未知错误",e.getMessage(),e);
        }
    }

    //发送消息给客户端
    public void sendMessage(MyMessage data) {
        try {
            log.info("发送消息:"+data);
            this.session.getBasicRemote().sendObject(ResultData.success(data));
        } catch (EncodeException e) {
            throw new MyException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //连接成功
    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid) {
        this.session = session;
        this.uid = uid;
        //添加到session中
        sessions.put(uid,this);
        log.info(uid+" 连接成功，当前连接人数为："+sessions.size());
        //检查缓存数据
        List<MyMessage> messages = redisCacheDao.getList(uid,MyMessage.class);
        log.info("查询缓存:"+messages);
        //如果有缓存数据
        if (messages != null){
            // 直接发给这个人
            for (MyMessage message:messages) {
                sendMessage(message);
            }
            // 删除缓存数据
            redisCacheDao.delete(uid);
        }
    }

    //连接断开
    @OnClose
    public void onClose() {
        //释放
        sessions.remove(this.uid);
        log.info("[WebSocket] 退出成功，当前连接人数为：={}", sessions.size());
    }

    //收到消息
    @OnMessage
    public String onMessage(String message) {
        log.info("[WebSocket] 收到消息：{}", message);

        //这里是自己测试的，可以忽略
        if (message.equals("一只羊")) {//不能用==
            return "1:1个大白羊";
        }
        if (message.equals("两只羊")) {
            return "2:2个大白羊";
        }
        if (message.equals("三只羊")) {
            return "3:个大白羊";
        }

        return "你已成功连接，这是webSocket服务端的返回信息！";
    }
}
